import { ConnectionPool } from '@/core/connection-pool';
import { Logger } from '@/types';
import { createLogger } from '@/utils/logger';

/**
 * Health check status
 */
export interface HealthStatus {
  status: 'healthy' | 'unhealthy' | 'degraded';
  timestamp: number;
  checks: {
    connection: {
      status: 'pass' | 'fail';
      message: string;
      responseTime?: number;
    };
    memory: {
      status: 'pass' | 'warn' | 'fail';
      usage: number;
      limit: number;
    };
    queues?: {
      status: 'pass' | 'warn' | 'fail';
      details: Array<{
        name: string;
        messageCount: number;
        consumerCount: number;
      }>;
    };
  };
  uptime: number;
  version: string;
}

/**
 * Health checker for RabbitMQ connections and system status
 */
export class HealthChecker {
  private readonly connectionPool: ConnectionPool;
  private readonly logger: Logger;
  private readonly startTime: number;
  private readonly memoryThreshold: number;

  constructor(
    connectionPool: ConnectionPool,
    options: {
      memoryThreshold?: number; // Memory threshold in MB
      logger?: Logger;
    } = {}
  ) {
    this.connectionPool = connectionPool;
    this.logger = options.logger ?? createLogger('HealthChecker');
    this.startTime = Date.now();
    this.memoryThreshold = options.memoryThreshold ?? 512; // 512MB default
  }

  /**
   * Perform comprehensive health check
   */
  async checkHealth(): Promise<HealthStatus> {
    const timestamp = Date.now();
    const uptime = timestamp - this.startTime;

    try {
      // Check connection
      const connectionCheck = await this.checkConnection();

      // Check memory usage
      const memoryCheck = this.checkMemory();

      // Check queues (optional)
      const queueCheck = await this.checkQueues();

      // Determine overall status
      const checks = {
        connection: connectionCheck,
        memory: memoryCheck,
        ...(queueCheck && { queues: queueCheck }),
      };

      const status = this.determineOverallStatus(checks);

      return {
        status,
        timestamp,
        checks,
        uptime,
        version: '1.0.0', // Should be imported from package.json
      };
    } catch (error) {
      this.logger.error('Health check failed', error as Error);

      return {
        status: 'unhealthy',
        timestamp,
        checks: {
          connection: {
            status: 'fail',
            message: `Health check error: ${(error as Error).message}`,
          },
          memory: this.checkMemory(),
        },
        uptime,
        version: '1.0.0',
      };
    }
  }

  /**
   * Check RabbitMQ connection health
   */
  private async checkConnection(): Promise<HealthStatus['checks']['connection']> {
    const startTime = Date.now();

    try {
      const connection = await this.connectionPool.getConnection();

      // Test the connection by creating a temporary channel
      const channel = connection.channel;
      await channel.checkQueue(''); // This will fail gracefully if connection is bad

      await this.connectionPool.returnConnection(connection);

      const responseTime = Date.now() - startTime;

      return {
        status: 'pass',
        message: 'Connection is healthy',
        responseTime,
      };
    } catch (error) {
      return {
        status: 'fail',
        message: `Connection failed: ${(error as Error).message}`,
        responseTime: Date.now() - startTime,
      };
    }
  }

  /**
   * Check memory usage
   */
  private checkMemory(): HealthStatus['checks']['memory'] {
    const memoryUsage = process.memoryUsage();
    const usedMB = Math.round(memoryUsage.heapUsed / 1024 / 1024);
    const limitMB = this.memoryThreshold;

    let status: 'pass' | 'warn' | 'fail';

    if (usedMB > limitMB) {
      status = 'fail';
    } else if (usedMB > limitMB * 0.8) {
      status = 'warn';
    } else {
      status = 'pass';
    }

    return {
      status,
      usage: usedMB,
      limit: limitMB,
    };
  }

  /**
   * Check queue health (optional, requires queue names)
   */
  private async checkQueues(
    queueNames?: string[]
  ): Promise<HealthStatus['checks']['queues'] | undefined> {
    if (!queueNames || queueNames.length === 0) {
      return undefined;
    }

    try {
      const connection = await this.connectionPool.getConnection();
      const channel = connection.channel;

      const queueDetails = [];
      let hasWarnings = false;
      let hasErrors = false;

      for (const queueName of queueNames) {
        try {
          const queueInfo = await channel.checkQueue(queueName);

          queueDetails.push({
            name: queueName,
            messageCount: queueInfo.messageCount,
            consumerCount: queueInfo.consumerCount,
          });

          // Check for potential issues
          if (queueInfo.messageCount > 10000) {
            hasWarnings = true;
          }

          if (queueInfo.consumerCount === 0 && queueInfo.messageCount > 0) {
            hasWarnings = true;
          }
        } catch (error) {
          hasErrors = true;
          queueDetails.push({
            name: queueName,
            messageCount: -1,
            consumerCount: -1,
          });
        }
      }

      await this.connectionPool.returnConnection(connection);

      let status: 'pass' | 'warn' | 'fail';
      if (hasErrors) {
        status = 'fail';
      } else if (hasWarnings) {
        status = 'warn';
      } else {
        status = 'pass';
      }

      return {
        status,
        details: queueDetails,
      };
    } catch (error) {
      return {
        status: 'fail',
        details: [],
      };
    }
  }

  /**
   * Determine overall health status
   */
  private determineOverallStatus(checks: HealthStatus['checks']): HealthStatus['status'] {
    const statuses = [
      checks.connection.status,
      checks.memory.status,
      ...(checks.queues ? [checks.queues.status] : []),
    ];

    if (statuses.includes('fail')) {
      return 'unhealthy';
    }

    if (statuses.includes('warn')) {
      return 'degraded';
    }

    return 'healthy';
  }

  /**
   * Get connection pool statistics
   */
  getConnectionStats(): {
    totalConnections: number;
    availableConnections: number;
    busyConnections: number;
    poolSize: number;
  } {
    return this.connectionPool.getStats();
  }

  /**
   * Get system information
   */
  getSystemInfo(): {
    nodeVersion: string;
    platform: string;
    arch: string;
    uptime: number;
    memory: NodeJS.MemoryUsage;
    cpuUsage: NodeJS.CpuUsage;
  } {
    return {
      nodeVersion: process.version,
      platform: process.platform,
      arch: process.arch,
      uptime: process.uptime(),
      memory: process.memoryUsage(),
      cpuUsage: process.cpuUsage(),
    };
  }
}

/**
 * Utility function to create health checker
 */
export const createHealthChecker = (
  connectionPool: ConnectionPool,
  options?: {
    memoryThreshold?: number;
    logger?: Logger;
  }
): HealthChecker => {
  return new HealthChecker(connectionPool, options);
};
